Skip to main content
Version: 2.0

Upload Media For Template

Objective

To upload media files directly onto Meta servers — either via a publicly accessible URL or from a local file — without requiring a permanent public hosting URL.

Benefits:

  • Better security since files do not need to be hosted on a public URL
  • Eliminates dependency on external hosting

Before You Start

This guide assumes you have read the Before You Start section.

You will need:

  • A file in one of the following formats: pdf, jpeg, jpg, png
  • A user access token

Authentication

Media Upload APIs are accessed using a Bearer token. Use the endpoint below to generate one.

Request Type: POST

UAT Endpoint: https://apiuat.aclwhatsapp.com/auth/realms/ipmessaging/protocol/openid-connect/token

curl --location \
'https://apiuat.aclwhatsapp.com/auth/realms/ipmessaging/protocol/openid-connect/token' \
--header 'cache-control: no-cache' \
--header 'content-type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id=ipmessaging-client' \
--data-urlencode 'username=username' \
--data-urlencode 'password=password'

Header Values

NameValue
cache-controlno-cache
content-typeapplication/x-www-form-urlencoded

Data Object Values

NameDescriptionValue
grant_typeAuthentication methodpassword
usernameProvided by Sinch at onboarding
client_idFixed valueipmessaging-client
passwordProvided by Sinch at onboarding

Response

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAi",
"expires_in": 300,
"token_type": "Bearer",
"not-before-policy": 0,
"session_state": "f2cd48bf-d162-4754-b2c7-bdc9c97064b3",
"scope": "email profile"
}
NameDescription
access_tokenToken to be used in subsequent API calls
expires_inToken validity in seconds
token_typeFixed value — Bearer

Media Upload

The media upload for templates is a 2-step process.


Step 1 — Upload Media & Get Acknowledgement ID

Send a POST request to upload your media. You can upload via a public URL or directly from a local file.


Method A — Upload via Public URL

UAT Endpoint: https://apiuat.aclwhatsapp.com/access-api/api/v1/wa/{waba-id}/media/upload

Production Endpoint: https://api.aclwhatsapp.com/access-api/api/v1/wa/{waba-id}/media/upload

curl --location \
'https://apiuat.aclwhatsapp.com/access-api/api/v1/wa/{waba-id}/media/upload' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <token>' \
--data '{
"mediaUrl": "https://download.samplelib.com/mp3/sample-3s.mp3",
"mediaFormat": "audio/mpeg",
"always_upload": false
}'

Header Values

NameValue
Content-Typeapplication/json
AuthorizationBearer token

Method B — Upload from Local File

Use this method to upload a media file directly from your local system without requiring a public URL.

UAT Endpoint: https://apiuat.aclwhatsapp.com/access-api/api/v1/wa/{waba-id}/media/file/upload

Production Endpoint: https://api.aclwhatsapp.com/access-api/api/v1/wa/{waba-id}/media/file/upload

curl --location \
'https://apiuat.aclwhatsapp.com/access-api/api/v1/wa/<waba_id>/media/file/upload' \
--header 'Authorization: Bearer <token>' \
--form 'mediaFormat="image/png"' \
--form 'always_upload="true"' \
--form 'file=@"/<path-to-local-file>"'

Header Values

NameValue
AuthorizationBearer token

Data Object Values

NameDescriptionValue
mediaFormatMIME type of the media as supported by Metae.g. image/png
always_uploadRe-upload even if a mediaId already existstrue / false
filePath to the local filee.g. /home/user/image.png

Response (both methods)

{
"acknowledgementId": "1752915620015378432",
"acceptedTime": 1706762626066
}

Error & Exceptions

  1. Duplicate Request (without always_upload) — Multiple requests for the same file with always_upload: false.
{
"mediaId": "6fba7ef1-f845-4063-b96a-f814058213f2",
"acknowledgementId": "1752915620015378432",
"error": "duplicate.media.upload.request"
}
  1. Duplicate Request (with always_upload) — Multiple requests for the same file with always_upload: true, but the existing media was uploaded within the last 7 days.
{
"mediaId": "6fba7ef1-f845-4063-b96a-f814058213f2",
"acknowledgementId": "1752915620015378432",
"error": "duplicate.media.upload.request"
}

If the media exists but was uploaded more than 7 days ago, the system will allow re-upload and generate a new acknowledgement ID.

  1. Rate Limit Error — Enterprises can upload a maximum of 5 media files per minute. Maximum file size is 20 MB.
{
"error": "request.limit.exceeded"
}
{
"error": "File size limit exceeds"
}
  1. Media Already Uploaded — Media was previously uploaded and is still active.
{
"mediaId": "65402eb9-755d-44ef-a9d4-666e48c60708",
"acknowledgementId": "1788877842411425792",
"error": "duplicate.media.upload.request"
}

Step 2 — Fetch Media ID using Acknowledgement ID

After receiving the acknowledgement ID, use the request below to retrieve the Media ID required for sending template messages.

UAT Endpoint: https://apiuat.aclwhatsapp.com/access-api/api/v1/wa/{waba-id}/media

Production Endpoint: https://api.aclwhatsapp.com/access-api/api/v1/wa/{waba-id}/media

Request Type: POST

curl --location \
'https://apiuat.aclwhatsapp.com/access-api/api/v1/wa/{waba-id}/media' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{"acknowledgementId": "<acknowledgementId>"}'

Header Values

NameValue
Content-Typeapplication/json
AuthorizationBearer token

Data Object Values

NameDescriptionValue
acknowledgementIdID generated in Step 11752915620015378432

Response

{
"mediaId": "1186780792327418",
"acknowledgementId": "1752915620015378432",
"mediaUrl": "https://download.samplelib.com/mp3/sample-3s.mp3",
"expiryTime": 1707972226000,
"status": "success"
}

Response Details

FieldDescription
mediaIdUse this to send the template message
acknowledgementIdProvided in the request
mediaUrlThe URL of the uploaded media
expiryTimeTimestamp until which media is available on Meta servers. Re-upload required after expiry.

Error & Exceptions

  1. Upload In Progress — Media upload is still being processed at Meta servers.
{
"acknowledgementId": "1755474606652657662",
"mediaUrl": "",
"expiryTime": null,
"status": "media.generation.in.progress",
"errors": [
{
"desc": "Media upload is in progress"
}
]
}
  1. Media Not Found — Media has expired.
{
"acknowledgementId": "1755473752088383468",
"status": "media.not.found"
}
  1. Media Generation Failed — Upload failed at Meta servers.
{
"acknowledgementId": "1755477593324261376",
"mediaUrl": "",
"expiryTime": null,
"status": "media.generation.failed",
"errors": [
{
"code": "502",
"desc": "Something went wrong while generating mediaId, please try again"
}
]
}